package top.lingkang.mm.orm;

import cn.hutool.core.lang.Assert;
import top.lingkang.mm.error.MagicException;

import java.util.*;

/**
 * @author lingkang
 * @create by 2025/1/8 18:00
 * @since 1.1.1
 */
public class BaseQuery  {
    protected List<ConditionValue> list = new ArrayList<>();
    protected List<ConditionOrderBy> orderBy;
    protected String sql = "";
    protected HashMap<String, Object> param = new HashMap<>();
    protected static final Map<Condition, ConditionHandler> handlers = new HashMap<>();

    static {
        QueryUtils.initHandler(handlers);
    }

    public BaseQuery symbol(String column, String symbol, Object value) {
        list.add(new ConditionValue(Condition.symbol, column, value).setSymbol(symbol));
        return this;
    }

    public BaseQuery eq(String column, Object value) {
        list.add(new ConditionValue(Condition.eq, column, value));
        return this;
    }

    public BaseQuery ne(String column, Object value) {
        list.add(new ConditionValue(Condition.ne, column, value));
        return this;
    }

    public BaseQuery gt(String column, Object value) {
        list.add(new ConditionValue(Condition.gt, column, value));
        return this;
    }

    public BaseQuery ge(String column, Object value) {
        list.add(new ConditionValue(Condition.ge, column, value));
        return this;
    }

    public BaseQuery lt(String column, Object value) {
        list.add(new ConditionValue(Condition.lt, column, value));
        return this;
    }

    public BaseQuery le(String column, Object value) {
        list.add(new ConditionValue(Condition.le, column, value));
        return this;
    }

    public BaseQuery like(String column, Object value) {
        list.add(new ConditionValue(Condition.like, column, value));
        return this;
    }

    public BaseQuery notLike(String column, Object value) {
        list.add(new ConditionValue(Condition.notLike, column, value));
        return this;
    }

    public BaseQuery likeLeft(String column, Object value) {
        list.add(new ConditionValue(Condition.likeLeft, column, value));
        return this;
    }

    public BaseQuery likeRight(String column, Object value) {
        list.add(new ConditionValue(Condition.likeRight, column, value));
        return this;
    }

    public BaseQuery notLikeLeft(String column, Object value) {
        list.add(new ConditionValue(Condition.notLikeLeft, column, value));
        return this;
    }

    public BaseQuery notLikeRight(String column, Object value) {
        list.add(new ConditionValue(Condition.notLikeRight, column, value));
        return this;
    }

    /**
     * column is null
     */
    public BaseQuery isNull(String column) {
        list.add(new ConditionValue(Condition.isNull, column, null));
        return this;
    }

    /**
     * column is not null
     */
    public BaseQuery isNotNull(String column) {
        list.add(new ConditionValue(Condition.isNotNull, column, null));
        return this;
    }

    /**
     * <pre>
     * {@code
     *     new Query().in("id", Arrays.asList(1, 19951219, 3))
     * }
     * </pre>
     */
    public BaseQuery in(String column, Collection value) {
        list.add(new ConditionValue(Condition.in, column, value));
        return this;
    }

    /**
     * <pre>
     * {@code
     *     new Query().notIn("id", Arrays.asList(1, 19951219, 3))
     * }
     * </pre>
     */
    public BaseQuery notIn(String column, Collection value) {
        list.add(new ConditionValue(Condition.notIn, column, value));
        return this;
    }

    public BaseQuery orderByAsc(String... ascColumn) {
        Assert.notNull(ascColumn, "排序的列不能为空");
        if (orderBy == null)
            orderBy = new ArrayList<>();
        orderBy.add(new ConditionOrderBy(Condition.orderByAsc, ascColumn));
        return this;
    }

    public BaseQuery orderByDesc(String... descColumn) {
        Assert.notNull(descColumn, "排序的列不能为空");
        if (orderBy == null)
            orderBy = new ArrayList<>();
        orderBy.add(new ConditionOrderBy(Condition.orderByDesc, descColumn));
        return this;
    }

    public BaseQuery or() {
        list.add(new ConditionValue(Condition.or));
        return this;
    }

    /**
     * 追加sql，注意顺序，查询中存在 orderByAsc 或者 orderByAsc 时，<br>
     * orderByAsc 或者 orderByAsc 将会生成到sql最后面<br>
     * 例如 new Query().orderByAsc("id").sql(" name=#{name}") 报错<br>
     * 将会输出错误sql：select * from my_table order by id asc name=#{name}
     *
     * @param sql 要追加的sql，例如 limit 1，输出sql：select id from t_user where 1=1 limit 1
     * @return 追加sql
     */
    public BaseQuery sql(String sql) {
        list.add(new ConditionValue(Condition.sql, sql, null));
        return this;
    }

    /**
     * 追加sql，注意顺序，查询中存在 orderByAsc 或者 orderByAsc 时，<br>
     * orderByAsc 或者 orderByAsc 将会生成到sql最后面<br>
     * 例如 new Query().orderByAsc("id").sql(" name=#{name}") 报错<br>
     * 将会输出错误sql：select * from my_table order by id asc name=#{name}
     *
     * @param sql   id = #{id} and type= #{type}
     * @param param new MapParam().add("id","1").add("type","user")
     * @return 查询对象
     */
    public BaseQuery sql(String sql, Map<String, Object> param) {
        list.add(new ConditionValue(Condition.sql, sql, param));
        return this;
    }

    public String buildSql() {
        StringBuilder str_ = new StringBuilder();
        boolean isOr = false;
        int i = 1;
        for (ConditionValue conditionValue : list) {
            Condition key = conditionValue.getCondition();
            if (key == Condition.or) {
                str_.append(" or ");
                isOr = true;
                continue;
            } else if (key == Condition.sql) {
                str_.append(" ").append(conditionValue.getColumn());
                Object value = conditionValue.getValue();
                if (value != null) {
                    param.putAll((Map<String, Object>) value);
                }
                return str_.toString();
            } else if (!isOr)
                str_.append(" and ");
            else
                isOr = false;

            // 条件
            String p = "p" + i++;
            handlers.get(conditionValue.getCondition()).handle(str_, this, conditionValue, p);
        }

        if (orderBy != null) {
            boolean has = false;
            for (ConditionOrderBy by : orderBy) {
                if (by.getColumns() == null || by.getColumns().length == 0)
                    throw new MagicException("orderBy 排序列入参不能为空！");

                if (!has) {
                    str_.append(" order by ");
                } else
                    str_.append(", ");
                if (by.getBy() == Condition.orderByAsc) {// asc
                    if (!has)
                        str_.append(MagicEntityUtils.getOrderBy(by.getColumns())).append(" asc");
                    else
                        str_.append(MagicEntityUtils.getOrderBy(by.getColumns(), "asc"));
                } else if (by.getBy() == Condition.orderByDesc) {// desc
                    if (!has)
                        str_.append(MagicEntityUtils.getOrderBy(by.getColumns())).append(" desc");
                    else
                        str_.append(MagicEntityUtils.getOrderBy(by.getColumns(), "desc"));
                }
                has = true;
            }
        }

        return str_.toString();
    }

    protected void addQueryParam(StringBuilder sql, String p) {
        sql.append("#{").append(BaseMapperSql.param_q).append(".param.").append(p).append("}");
    }


    // get 、 set

    // mybatis的底层将会调用获取SQL
    public String getSql() {
        if (list.isEmpty() && orderBy == null)
            return "";
        return "where 1=1" + buildSql();
    }

    public void setSql(String sql) {
        this.sql = sql;
    }

    public HashMap<String, Object> getParam() {
        return param;
    }

    public void setParam(HashMap<String, Object> param) {
        this.param = param;
    }
}
